package com.shizhi.usp.pl2303;

import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.os.AsyncTaskCompat;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

import com.felhr.usbserial.UsbSerialDevice;
import com.felhr.usbserial.UsbSerialInterface;
import com.shizhi.usp.R;
import com.shizhi.usp.base.BaseSerialFra;

import java.lang.reflect.Field;
import java.util.Locale;

import tw.com.prolific.pl2303multilib.PL2303MultiLib;

/**
 * A simple {@link Fragment} subclass.
 * Activities that contain this fragment must implement the
 * Use the {@link Pl2303Fragment#newInstance} factory method to
 * create an instance of this fragment.
 */
public class Pl2303Fragment extends BaseSerialFra {
    // TODO: Rename parameter arguments, choose names that match
    // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
    private static final String ARG_PARAM1 = "param1";
    private static final String ARG_PARAM2 = "param2";

    // TODO: Rename and change types of parameters
    private String mParam1;
    private String mParam2;

    public Pl2303Fragment() {
        // Required empty public constructor
    }

    /**
     * Use this factory method to create a new instance of
     * this fragment using the provided parameters.
     *
     * @return A new instance of fragment Pl2303Fragment.
     */
    // TODO: Rename and change types and number of parameters
    public static Pl2303Fragment newInstance() {
        Pl2303Fragment fragment = new Pl2303Fragment();
        Bundle args = new Bundle();
        args.putString(ARG_PARAM1, "");
        args.putString(ARG_PARAM2, "");
        fragment.setArguments(args);
        return fragment;
    }

    private static final String ACTION_USB_PERMISSION = "com.prolific.pluartmultisimpletest.USB_PERMISSION";
    private PL2303MultiLib mPort;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mPort = new PL2303MultiLib(mUsbManager, getActivity(), ACTION_USB_PERMISSION);
        IntentFilter filter = new IntentFilter();
        filter.addAction(mPort.PLUART_MESSAGE);
        getActivity().registerReceiver(PLMultiLibReceiver, filter);
        if (getArguments() != null) {
            mParam1 = getArguments().getString(ARG_PARAM1);
            mParam2 = getArguments().getString(ARG_PARAM2);
        }
    }


    @Override
    public void onDestroy() {
        getActivity().unregisterReceiver(PLMultiLibReceiver);
        super.onDestroy();
    }

    private final BroadcastReceiver PLMultiLibReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(mPort.PLUART_MESSAGE)) {
                Bundle extras = intent.getExtras();
                if (extras != null) {
                    String str = (String) extras.get(mPort.PLUART_DETACHED);
                    Toast.makeText(context, "onReceive: usb port is detached : " + str, Toast.LENGTH_SHORT).show();
                }
            }
        }
    };

    private int INDEX = 0;
    private static final String TAG = "Pl2303Fragment";

    /**
     * 打开串口
     */
    @Override
    public boolean openSerial() {

        AsyncTaskCompat.executeParallel(new AsyncTask<Object, Object, String>() {
            @Override
            protected String doInBackground(Object... params) {
                String result = "請配置串口！！！";
                final String[] port = getSerialPort();
                if (port != null) {
                    UsbDevice device = mUsbManager.getDeviceList().get(port[0]);
                    if (device != null) {
                        if (!mUsbManager.hasPermission(device)) {
                            mUsbManager.requestPermission(device, PendingIntent.getActivity(mActivity, 100, new Intent(""), 0));
                        }
                        int wating = 10;
                        boolean flag = false;
                        while (true) {
                            wating--;
                            if (wating < 0) break;
                            if (mUsbManager.hasPermission(device)) {
                                flag = true;
                                break;
                            }
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                break;
                            }
                        }
                        if (flag) {
                            try {
                                final String deviceName = device.getDeviceName();
                                if (mPort == null)
                                    mPort = new PL2303MultiLib(mUsbManager, getActivity(), ACTION_USB_PERMISSION);
                                int count = mPort.PL2303Enumerate();
                                if (count <= 0) {
                                    Log.e(TAG, String.format("Usb转串口打开中: Usb转串口不存在，请检查Usb连接与否 count: %s,index:%s ,index<count:%s"
                                            , count, INDEX, INDEX < count));
//                                    throw new SecurityException(String.format("Usb转串口打开中: Usb转串口不存在 ，请检查Usb连接与否 count: %s,index:%s ,index<count:%s"
//                                            , count, INDEX, INDEX < count));
                                    return "串口打开失败100";
                                }
                                //根据唯一文件地址获取设备路径名
                                //反射获取下标
                                int enumerateIndex = -1;
                                try {
                                    Field mDeviceInfoListField = mPort.getClass().getDeclaredField("ab");
                                    mDeviceInfoListField.setAccessible(true);
                                    Object[] mDeviceInfoList = (Object[]) mDeviceInfoListField.get(mPort);
                                    int index = 0;
                                    for (Object deviceInfo : mDeviceInfoList) {
                                        ///dev/bus/usb/003/006
                                        Field devicePathField = deviceInfo.getClass().getDeclaredField("f");
                                        devicePathField.setAccessible(true);
                                        String devicePath = (String) devicePathField.get(deviceInfo);
                                        if (TextUtils.isEmpty(devicePath)) continue;
                                        Log.d(TAG, "form Enumerate list: find path: " + devicePath);
                                        onStatuChanged("\r\n\tform Enumerate list: find path: " + devicePath);
                                        if (deviceName.equals(devicePath)) {
                                            enumerateIndex = index;
                                            break;
                                        }
                                        index++;
                                    }
                                } catch (Exception e) {
                                    onStatuChanged("\r\n\tform Enumerate list: Exception : \r\n" + e.toString());
                                    //e.printStackTrace();
                                }

                                if (enumerateIndex < count && enumerateIndex >= 0) {
                                    INDEX = enumerateIndex;
                                    Log.d(TAG, String.format("Usb转串口打开中: 设备路径为%s 的下标为:%s ", deviceName, INDEX));
                                } else {
                                    Log.d(TAG, String.format("Usb转串口打开失败1: 设备路径为%s 的下标不存在 enumerateIndex:%s count:%s", deviceName, enumerateIndex, count));
                                    onStatuChanged("\r\n\t串口打开失败101, enumerateIndex:" + enumerateIndex);
                                    INDEX = 0;
                                }

                                //打开INDEX
                                if (mPort.PL2303IsDeviceConnectedByIndex(INDEX)) {
                                    Log.w(TAG, "open: also connected");
                                    try {
                                        mPort.PL2303CloseDeviceByIndex(INDEX);
                                    } catch (Exception e) {
                                        //Log.e(TAG, "open: ", e);
                                    }
                                }

                                PL2303MultiLib.BaudRate targetBaudRate = null;
                                if (Integer.valueOf(port[1]) == 9600) {
                                    targetBaudRate = PL2303MultiLib.BaudRate.B9600;
                                } else if (Integer.valueOf(port[1]) == 115200) {
                                    targetBaudRate = PL2303MultiLib.BaudRate.B115200;
                                } else {
                                    return "串口打开失败103";
                                }
                                boolean succeed = mPort.PL2303OpenDevByUARTSetting(INDEX,
                                        targetBaudRate, PL2303MultiLib.DataBits.D8
                                        , PL2303MultiLib.StopBits.S1, PL2303MultiLib.Parity.NONE
                                        , PL2303MultiLib.FlowControl.OFF);
                                if (!succeed) {
                                    result = "打開失敗";
                                } else {
                                    new Thread(new AutoReadThread()).start();
                                    result = "打開成功";
                                }
                            } catch (Exception e) {
                                Log.e(TAG, "doInBackground: ", e);
                                result = "串口打开失败104" + e.toString();
                                return result;
                            }
                        } else {
                            //没权限
                            result = "串口打开失败105";
                        }
                    }
                }
                return result;
            }

            @Override
            protected void onPostExecute(String s) {
                super.onPostExecute(s);
                Toast.makeText(mActivity, s, Toast.LENGTH_SHORT).show();
            }
        });
        return false;
    }

    final Object mLock = new Object();

    @Override
    public void closeSerial() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (mLock) {
                    if (mPort != null)
                        mPort.PL2303Release();
                    mPort = null;
                }
            }
        }).start();

    }

    @Override
    public void writeData(byte[] data) {
        if (mPort != null && data.length > 0) {
            mPort.PL2303Write(INDEX, data);
        }
    }

    @Override
    public void writeData(byte[] data, int offset, int len) {

    }

    class AutoReadThread implements Runnable {

        @Override
        public void run() {
            while (mPort != null) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (mLock) {
                    if (mPort != null && mPort.PL2303IsDeviceConnectedByIndex(INDEX)) {
                        byte[] data = new byte[512];
                        int readLen = mPort.PL2303Read(INDEX, data);
                        if (readLen > 0) {
                            byte[] newData = new byte[readLen];
                            System.arraycopy(data, 0, newData, 0, readLen);
//                            Log.d(TAG, "run: "+new String(newData));
                            receiverData(newData);
                        }
                    }
                }
            }
        }
    }

}
